﻿import json
import pickle
import time

from PySide6.QtCore import QThread, Signal, QByteArray
from PySide6.QtNetwork import QUdpSocket, QHostAddress
from Devices.Device import Device, ChiotDevice, AndlinkDevice
from .AesCipher import AesCbc

class DeviceScanner(QThread):
    DeviceOnline = Signal(Device)

    def __init__(self):
        super().__init__()
        self.__QUdpSocket = QUdpSocket()
        self.__QUdpSocket.readyRead.connect(self.on_readPendingDatagrams)
        self.__QUdpSocket.bind(QHostAddress.Any)

    def __del__(self):
        if (self.__QUdpSocket is not None):
            self.__QUdpSocket.disconnectFromHost()
            self.__QUdpSocket.close()
            del self.__QUdpSocket
            self.__QUdpSocket = None
        self.terminate()

    def run(self):
        obj = {"client" : "NetworkTestTool"}
        sendData = QByteArray(json.dumps(obj, separators=(',', ':')))
        
        objEncrypt = {"client" : "NetworkTest","cmd":"deviceSearch", "time":int(round(time.time() * 1000))}

        #coap发现字节:VTEùNµqlinksearchdeviceÿ{"searchKey": "ANDLINK-DISCOVER", "andlinkVersion" : "V3"}
        coapBytesArrayDISCOVER = (0x56, 0x02, 0x54, 0x45, 0x05, 0x98, 0x98, 0x90, 0xf9, 0x4e, 0xb5, 0x71, 0x6c, 0x69, 0x6e, 0x6b,
            0x0c, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0xff, 0x7b, 0x22,
            0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x4e, 0x44,
            0x4c, 0x49, 0x4e, 0x4b, 0x2d, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x22, 0x2c, 0x20,
            0x22, 0x61, 0x6e, 0x64, 0x6c, 0x69, 0x6e, 0x6b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22,
            0x20, 0x3a, 0x20, 0x22, 0x56, 0x33, 0x22, 0x7d, 0x00)
        coapBytesDISCOVER = pickle.dumps(coapBytesArrayDISCOVER)

        #coap发现字节:TT4^}µqlinksearchdeviceDtrueÿ{"searchKey": "ANDLINK-APP", "andlinkVersion" : "V3"}
        coapBytesArrayAPP = (0x54, 0x02, 0x54, 0x34, 0x5e, 0x7d, 0x0b, 0x87, 0xb5, 0x71, 0x6c, 0x69, 0x6e, 0x6b, 0x0c, 0x73,
            0x65, 0x61, 0x72, 0x63, 0x68, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x74, 0x72, 0x75, 0x65,
            0xff, 0x7b, 0x22, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x22, 0x3a, 0x20, 0x22,
            0x41, 0x4e, 0x44, 0x4c, 0x49, 0x4e, 0x4b, 0x2d, 0x41, 0x50, 0x50, 0x22, 0x2c, 0x20, 0x22, 0x61,
            0x6e, 0x64, 0x6c, 0x69, 0x6e, 0x6b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x20, 0x3a,
            0x20, 0x22, 0x56, 0x33, 0x22, 0x7d, 0x00)
        coapBytesAPP = pickle.dumps(coapBytesArrayAPP)

        sleepTime = 1.0
        MAX_TIME = 3
        for i in range(MAX_TIME):
            objEncrypt["time"] = int(round(time.time() * 1000))
            sendDataEncrypt = QByteArray(AesCbc().encrypt(json.dumps(objEncrypt, separators=(',', ':'))))
            
            #普通广播和组播
            self.__QUdpSocket.writeDatagram(sendData, QHostAddress.Broadcast, 14444)
            self.__QUdpSocket.writeDatagram(sendData, QHostAddress("232.10.11.13"), 14444)
            
            self.__QUdpSocket.writeDatagram(sendDataEncrypt, QHostAddress.Broadcast, 14444)
            self.__QUdpSocket.writeDatagram(sendDataEncrypt, QHostAddress("232.10.11.13"), 14444)

            #MDNS端口的广播和组播
            self.__QUdpSocket.writeDatagram(sendData, QHostAddress.Broadcast, 5353)
            self.__QUdpSocket.writeDatagram(sendData, QHostAddress("224.0.0.251"), 5353)
			
            self.__QUdpSocket.writeDatagram(sendDataEncrypt, QHostAddress.Broadcast, 5353)
            self.__QUdpSocket.writeDatagram(sendDataEncrypt, QHostAddress("224.0.0.251"), 5353)

            #Andlink的设备查找
            self.__QUdpSocket.writeDatagram(coapBytesDISCOVER, QHostAddress.Broadcast, 5683)
            self.__QUdpSocket.writeDatagram(coapBytesAPP, QHostAddress.Broadcast, 5683)
            if (i < MAX_TIME - 1):
                QThread.sleep(sleepTime)
                sleepTime *= 2

    def on_readPendingDatagrams(self):
        while (self.__QUdpSocket.hasPendingDatagrams()):
            buff, addr, port = self.__QUdpSocket.readDatagram(256)
            if (buff.length() > 0):
                #print(buff)

                addStr:str = addr.toString()
                addStr = addStr[addStr.rfind(':') + 1:]
                msg:str = buff.data().decode()

                if ("DeviceOnline" in msg):
                    device = ChiotDevice(addStr, msg)
                    self.DeviceOnline.emit(device)
                elif ("searchAck" in msg):
                    device = AndlinkDevice(addStr, msg)
                    self.DeviceOnline.emit(device)
                else:
                    msg = AesCbc().decrypt(buff.data().decode())

                    if ("DeviceOnline" in msg):
                        device = ChiotDevice(addStr, msg)
                        self.DeviceOnline.emit(device)
                    elif ("searchAck" in msg):
                        device = AndlinkDevice(addStr, msg)
                        self.DeviceOnline.emit(device)
                    else:
                        device = Device(addStr)
                        self.DeviceOnline.emit(device)



